2.16 Schleifen spielerisch
 
Wer das Gefühl hat, das Konzept der Schleifen verstanden zu haben, der kann die nächsten Seiten dieses Kapitels gerne überblättern. Wer dagegen ein paar (Übungs-)Aufgaben sucht oder einfach an anderen Beispielen die beiden Schleifentypen vertiefen möchte, der findet auf den nächsten Seiten Material.
2.16.1 Primzahlen
 
Eine Primzahl ist eine Zahl, die nur durch sich selbst und durch 1 teilbar ist. Also die Zahlen 2, 3, 5, 7, 13, ... Der Benutzer gibt eine Zahl in ein Textfeld ein, die daraufhin überprüft wird, ob es sich um eine Primzahl handelt oder nicht.
Sub Primzahl()
Dim dblZahl As Double
Dim dblZähler As Double
dblZahl = CDbl(Me.txtZahl.Text)
For dblZähler = 2 To System.Math.Sqrt(dblZahl)
If dblZahl Mod dblZähler = 0 Then
MessageBox.Show(dblZahl.ToString & _
" ist keine Primzahl" & vbCr & _
dblZähler.ToString & " ist ein Teiler")
Exit Sub
End If
Next dblZähler
MessageBox.Show(dblZahl.ToString & _
" ist eine Primzahl."
End Sub
Abbildung 2.38
Keine Primzahl
Was tut das Programm? Der Benutzer gibt einen Wert in das Textfeld »txtZahl« ein - er wird an die Variable dblZahl übergeben. Ein Zähler dblZähler läuft nun von 2 (1 ist immer Teiler) bis zum Wert -1. Das wären zu viele Schritte. Man kann in der Mitte aufhören, denn wenn ein Teiler bis zur Mitte gefunden wird, dann hat er eine Entsprechung auf der »anderen« Seite. Die Mitte ist hier allerdings nicht die Hälfte, sondern die Wurzel. Man könnte den Ausdruck System.Math.Sqrt verkürzen, indem man vor das Programm schreibt:
Imports System.Math
Dann genügt Sqrt(dblZahl). Im nächsten Schritt wird überprüft, ob der Zähler die Zahl ohne Rest teilt. Dies erledigt der Operator »mod«. Beispiel:
7 mod 3 liefert 1 und 9 mod 3 ergibt 0.
Ist ein solcher Teiler gefunden, dann kann die Zahl keine Primzahl sein. Das wird gemeldet und das Programm beendet. Sollten alle in Frage kommenden Zahlen überprüft worden sein und kein Teiler wurde gefunden, dann ist klar, dass die eingegebene Zahl eine Primzahl ist.
Man könnte das Problem ebenso gut mit einer Do ... Loop-Schleife lösen.
Dim dblZahl As Double
Dim dblZähler As Double
dblZahl = CDbl(Me.txtZahl.Text)
dblZähler = 2
Do Until dblZähler > Sqrt(dblZahl)
If dblZahl Mod dblZähler = 0 Then
MessageBox.Show(dblZahl.ToString & _
" ist keine Primzahl" & vbCr & _
dblZähler.ToString & "ist ein Teiler")
Exit Sub
End If
dblZähler += 1
Loop
MessageBox.Show(dblZahl.ToString & " ist eine Primzahl")
Abbildung 2.39
Eine Primzahl
Das Prinzip ist sehr ähnlich. Zwei Unterschiede liegen vor: Die Schleife wird so lange ausgeführt, bis die Bedingung erfüllt ist. Während unser For ... Next-Beispiel einen Wert hochzählt, der verwendet werden kann, muss hier ein Zähler »installiert« werden:
dblZähler += 1
Übrigens: Solche »lang dauernden« Routinen können verwendet werden, um Rechnergeschwindigkeit zu testen. Dazu wird der Timer aus der Toolbox auf das Formular gezogen. Er öffnet am unteren Rand eine graue Leiste, auf der er sich automatisch anordnet. Allerdings wird der Timer niemals zur Laufzeit angezeigt. Es können auch mehrere Timer pro Dialog verwendet werden (siehe Abbildung 2.40).
Ein Doppelklick auf das Steuerelement liefert das Ereignis »Timer1_Tick«. Dort wird eine Variable hochgezählt. Angenommen, der Standardwert Intervall wird von 100 auf 10 verkleinert, so wird alle 10 Millisekunden oder 100 Mal pro Sekunde weitergezählt:
sngUhr += 10
Abbildung 2.40
Der Timer
Abbildung 2.41
Der Timer besitzt fast keine Eigenschaften.
Der Timer wird zu Beginn der Prozedur gestartet:
Timer1.Start()
Die Variable muss global deklariert werden und kann ausgegeben werden:
MessageBox.Show(dblZahl.ToString & _
" ist eine Primzahl" & vbCr & _
"Dafür waren " & Format(sngUhr, "0.000") & _
" Millisekunden nötig.")
Abbildung 2.42
Ganz schön schnell ...
Die Funktion Format beziehungsweise String.Format wird noch erläutert.
Ein anderes Prinzip der Primzahlenbestimmung heißt »Sieb des Eurysthenes«. Es wurde nach dem griechischen Mathematiker benannt und ist denkbar simpel. Man schreibe alle Zahlen von 2 bis zu einer beliebigen Obergrenze auf. Man nehme die 2 und überprüfe bei jeder Zahl, ob 2 Teiler ist. Falls ja, so wird diese Zahl gestrichen. Dann nehme man die 3, die 4, ... Übrig bleiben die Primzahlen.
So ähnlich kann man es programmieren. Der Benutzer gibt in ein Textfeld die Obergrenze ein. Es wird ein Array definiert, bei dem gilt :
dblZahlen(dblZähler) = dblZähler
Also beispielsweise: dblZahlen(3) = 3. Nun wird es ein bisschen knifflig. Eine Schleife zählt alle Werte vom ersten bis zum letzten hoch. Eine innere Schleife greift sich diesen Wert und überprüft ab Wert +1 alle Zahlen auf Teilbarkeit. Falls sie Teiler sind, wird der Wert 0 eingetragen.
Im letzten Schritt durchläuft eine Schleife alle Werte und sucht die Werte, die nicht 0 sind, um sie in der Listbox anzuzeigen:
Dim dblAnzahl As Double = _
CType(Me.txtAnzahl.Text, Double)
Dim dblZahlen(dblanzahl) As Double
Dim dblZähler As Double
Dim dblZähler2 As Double
For dblZähler = 2 To dblAnzahl
dblZahlen(dblZähler) = dblZähler
Next
For dblZähler = 2 To dblAnzahl
For dblZähler2 = dblZähler + 1 To dblAnzahl
If dblZahlen(dblZähler2) Mod _
dblZähler = 0 Then
dblZahlen(dblZähler2) = 0
End If
Next
Next
Me.ListBox1.Items.Clear()
For dblZähler = 2 To dblAnzahl
If dblZahlen(dblZähler) > 0 Then
Me.ListBox1.Items.Add(dblZähler.ToString)
End If
Next
Abbildung 2.43
Die ersten Primzahlen bis 100
2.16.2 Fibonacci-Zahlen
 
Noch ein Beispiel: Leonardo Fibonacci, ein italienischer Mathematiker, lebte zu Beginn des 13. Jahrhunderts. Er entdeckte eine Zahlenfolge, die entsteht, wenn man bei 1 beginnt und aus der Summe der beiden letzten Zahlen die nächste bildet: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 und so weiter. Mit dieser Zahlenfolge können logarithmische Spiralen beschrieben werden. Folgende Funktion erzeugt so lange neue Fibonacci-Zahlen, bis der Benutzer auf die Schaltfläche »Nein« klickt:
Sub Fibonacci_Zahlen()
Dim i1 As Integer = 1
Dim i2 As Integer = 1
Dim i3 As Integer
Dim bytantwort As Byte
Dim strFibonacci As String
strFibonacci = "1, 1"
Do Until bytantwort = DialogResult.No
i3 = i1 + i2
strFibonacci = _
strFibonacci & ", " & i3.ToString
i1 = i2 : i2 = i3
bytantwort = MessageBox.Show _
("Die letzte Fibonaccizahl war " & _
i3.ToString & _
"." & vbCr & "Die Reihe lautet: " & _
strFibonacci & vbCr & vbCr & _
"Möchten Sie eine weitere sehen?", _
"Fibonacci", MessageBoxButtons.YesNo)
Loop
In der Variable i1 wird der erste Wert gespeichert, in i2 der zweite. i3 ist die Summe auf beiden. Danach wird i2 an i1 übergeben, die Summe i3 an i2 und es kann erneut die Summe gebildet werden. Da zu Beginn des Programms nicht klar ist, wie viele Zahlen der Benutzer sehen möchte, muss mit einer Do ... Loop-Schleife gearbeitet werden.
Abbildung 2.44
Einige Fibonacci-Zahlen
2.16.3 ggT und kgV
 
Noch ein Beispiel: Gesucht ist der größte gemeinsame Teiler und das kleinste gemeinsame Vielfache zweier Zahlen. Auch hierfür gibt es, wie bei den Primzahlen, mehrere Varianten. Ich möchte eine davon vorstellen.
Beginnen wir mit dem größten gemeinsamen Teiler. Angenommen, die Zahlen lauten 12 und 16. Dann muss das Programm die kleinere von beiden ermitteln und mit Hilfe einer Schleife alle Zahlen ab dieser auf Teilbarkeit beider Zahlen überprüfen. Also, es wird getestet, ob 12 Teiler ist von 12 und 16, ob 11 Teiler ist von 12 und 16, ob 10 ... ob 4 Teiler ist von 12 und 16. Das zugehörige Programm könnte wie folgt aussehen:
Dim dblZ1 As Double = CType(Me.txtZahl1.Text, Double)
Dim dblZ2 As Double = CType(Me.txtZahl2.Text, Double)
Dim dblMin, dblZähler As Double
If dblZ1 < dblZ2 Then
dblMin = dblZ1
Else
dblMin = dblZ2
End If
For dblZähler = dblMin To 1 Step -1
If dblZ1 Mod dblZähler = 0 And _
dblZ2 Mod dblZähler = 0 Then
Me.txtZahl3.Text = dblZähler.ToString
Exit Sub
End If
Next
Abbildung 2.45
Der ggT von 124.688 und 96.424
In der Schleife wird immer ein gemeinsamer Teiler gefunden, denn die Zahl 1, die als letzte überprüft wird, teilt immer beide Zahlen.
Das kleinste gemeinsame Vielfache kann ähnlich berechnet werden: Ein Zähler läuft von der größeren der beiden Zahlen bis zum Produkt von beiden hoch und überprüft, ob beide Zahlen gleichzeitig Teiler sind. Falls ja, so wurde das kgV gefunden. Dieses Beispiel soll dem Leser zum Selbststudium überlassen bleiben.
Abbildung 2.46
Das kgV von 321 und 472
2.16.4 Ein Scherz zum Schluss
 
Dem Benutzer wird ein Button zur Verfügung gestellt, über welchen er gefragt wird, ob er eine Gehaltserhöhung haben möchte. Das Meldungsfenster beinhaltet die beiden Schaltflächen »Ja« und »Nein«.
Klickt der Benutzer auf »Ja«, so erscheint erneut der Dialog, klickt er auf »Ja« so kommt wieder das Meldungsfenster und so weiter. Erst wenn er sich entschließt auf »Nein« zu klicken, dann verschwindet das Fenster und der Anwender wird gelobt.
Auch dieser alberne Scherz funktioniert nur mit einer Do ... Loop-Schleife, da zu Beginn nicht klar ist, wie oft er auf »Ja« klicken wird. Die Prozedur könnte wie folgt aussehen:
Private Sub butGehaltserhöhung_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
butGehaltserhöhung.Click
Do Until MessageBox.Show _
("Möchten Sie eine Gehaltserhöhung?", "Mehr Knete", _
MessageBoxButtons.YesNo, MessageBoxIcon.Information) = _
DialogResult.No
Loop
MessageBox.Show("Braver Mitarbeiter", "Lob", _
MessageBoxButtons.Yes, MessageBoxIcon.Exclamtion)
End Sub
Abbildung 2.47
Es gibt keine Gehaltserhöhung!
Natürlich funktioniert es auch mit Do While ... = DialogResult.Yes. Wem das Beispiel zu knapp ist, der kann auch mit einer Variablen arbeiten, an die das Ergebnis des Meldungsfensters übergeben wird.
|